'use strict';

const { Service } = require('egg');
const { Op } = require('sequelize');
const ModelName = 'OrderGoods'
const { v4: uuidv4 } = require('uuid');
const dayjs = require("dayjs");
const config  = require("../../config/wx");
const configH5  = require("../../config/wxH5");
const path = require("path");
const fs = require("fs");
const crypto = require("crypto");
function generateNonceStr(len) {
    let data = "ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678";
    let str = "";
    for (let i = 0; i < len; i++) {
        str += data.charAt(Math.floor(Math.random() * data.length));
    }
    return str;
}

function createOrderNumber() {
  // 获取当前日期和时间
  let date = new Date();
  let year = date.getFullYear();
  let month = date.getMonth() + 1; // getMonth() 是从0开始的，所以需要+1
  let day = date.getDate();
  let hours = date.getHours();
  let minutes = date.getMinutes();
  let seconds = date.getSeconds();

  // 格式化日期和时间
  month = month < 10 ? '0' + month : month; // 如果月份小于10，前面添加一个0
  day = day < 10 ? '0' + day : day; // 如果日期小于10，前面添加一个0
  hours = hours < 10 ? '0' + hours : hours; // 如果小时小于10，前面添加一个0
  minutes = minutes < 10 ? '0' + minutes : minutes; // 如果分钟小于10，前面添加一个0
  seconds = seconds < 10 ? '0' + seconds : seconds; // 如果秒数小于10，前面添加一个0

  // 创建订单号
  return year + '' + month + '' + day + '' + hours + '' + minutes + '' + seconds;
}
class RouterService extends Service {
  /**
   * 根据分页和搜索条件获取
   * @param {Object} where 查询用户的条件
   * @param {Number} page 当前分页
   * @param {Number} pageSize 当前页每页多少条
   */
  async getPage(where, page, pageSize) {
    return this.ctx.model[ModelName].findAndCountAll({
        where: {
            ...where,
        },
      offset: pageSize * (page - 1),
      limit: pageSize,
      order:[
        // id 降序
        ['create_time','DESC'],
          ['start_time', 'DESC'],
          ['order_status', 'ASC']
      ],
      include: [

        { model: this.ctx.model.OrderGoodsDetail, include: [{ model: this.ctx.model.Goods }] },
        { model: this.ctx.model.Member },
        { model: this.ctx.model.Staff },
      ]
    });
  }

  // 所有列表
  async allList(where) {
    return this.ctx.model[ModelName].findAll({
      where: {
          ...where,
          is_del: 0
      },
      order:[
        // id 降序
        ['create_time','DESC'],
          ['start_time', 'DESC']
      ],
      include: [
        { model: this.ctx.model.OrderGoodsDetail, include: [{ model: this.ctx.model.Goods }] },
        { model: this.ctx.model.Member },
        { model: this.ctx.model.Staff },
      ]
    });
  }
  async findOne(id) {
    return this.ctx.model[ModelName].findOne({
      where: {
        id,
      },
      include: [
        { model: this.ctx.model.OrderGoodsDetail, include: [{ model: this.ctx.model.Goods }] },
        { model: this.ctx.model.Member },
        { model: this.ctx.model.Staff },
      ]
    });
  }
  async create(data) {
    const goodsIds = data.projects.map(el => el.id)
    const findGoodList = await this.app.model.Goods.findAll({
      where: {
        id: {
          [Op.in]: goodsIds
        },
        // 状态为启用
        status: 1
      }
    })
    if (findGoodList.length !== goodsIds.length) {
        throw new Error('服务不存在或者已经下架')
    }
    const memberDetail = await this.ctx.service.member.findOne(data.member_id)
    const staffDetail = data.staff_id ? await this.ctx.service.staff.findOne(data.staff_id) : null
    if (!memberDetail) {
        throw new Error('用户不存在')
    }
    if (data.staff_id && !staffDetail) {
        throw new Error('客服不存在')
    }
    if (data.staff_id && staffDetail.is_online === 0) {
        throw new Error('阿姨不在线')
    }
    const staff_ratio = data.staff_id ? (staffDetail.settlement_ratio || 60) / 100 : 0
    const orderDetailList = data.projects.map(el => {
          return {
              project_id: el.id,
              count: el.num,
              price: el.price,
              staff_price: el.price * staff_ratio,
              staff_ratio: data.staff_id ? staffDetail.settlement_ratio || 60 : 0
          }
      })
      const staff_amount = orderDetailList.reduce((prev, cur) => {
            return prev + cur.staff_price * cur.count
      },0)
    // 生成订单号
    const order_no = createOrderNumber()
    const insertData = {
        order_no,
        ...data,
        staff_amount,
    }
    if (data.pay_amount === 0) {
        insertData.pay_status = 1
    }
    const insertOrder = await this.ctx.model[ModelName].create(insertData)
    // 插入明细表
    await this.app.model.OrderGoodsDetail.bulkCreate(orderDetailList.map(item => {
        return {
            ...item,
            order_id: insertOrder.id,
        }
    }))
    return insertOrder
  }
  /**
   * 根据ID修改
   * @param {Number} id ID
   * @param {Object} data 要修改的信息
   */
  async update(id, data) {
      const transaction = await this.ctx.model.transaction();
      try {
          let serve_time = dayjs().format('YYYY-MM-DD HH:mm:ss')
          if (data.order_status === 3) {
              data.serve_time = serve_time
          }
          if (data.order_status === 4) {
                data.serve_end_time = serve_time
          }
          if (data.order_status === 1) {
              data.accept_time = serve_time
          }
          // 给客服加钱
          const orderDetailRes = await this.findOne(id)
          if (!orderDetailRes) {
             throw new Error('订单不存在')
          }
          const orderDetail = orderDetailRes.dataValues
          let staffDetail = null
          // 如果更新了员工ID，重新计算员工提成
          if (data.staff_id && data.staff_id !== orderDetail.staff_id) {
              staffDetail = await this.ctx.service.staff.findOne(data.staff_id)
              if (!staffDetail) {
                  throw new Error('客服不存在')
              }
              if (staffDetail.is_online === 0) {
                  throw new Error('阿姨不在线')
              }
              const staff_ratio = (staffDetail.settlement_ratio || 60) / 100
              
              // 获取订单明细
              const orderDetails = await this.app.model.OrderGoodsDetail.findAll({
                  where: { order_id: id },
                  transaction
              })
              
              // 重新计算每个明细的staff_price
              const updatedDetails = orderDetails.map(detail => {
                  const staff_price = detail.price * staff_ratio
                  return {
                      ...detail.dataValues,
                      staff_price,
                      staff_ratio: staffDetail.settlement_ratio || 60
                  }
              })
              
              // 计算总staff_amount
              const staff_amount = updatedDetails.reduce((prev, cur) => {
                  return prev + cur.staff_price * cur.count
              }, 0)
              
              // 更新订单明细
              for (const detail of updatedDetails) {
                  await this.app.model.OrderGoodsDetail.update({
                      staff_price: detail.staff_price,
                      staff_ratio: detail.staff_ratio
                  }, {
                      where: { id: detail.id },
                      transaction
                  })
              }
              
              // 更新订单的staff_amount
              data.staff_amount = staff_amount
          }

          // 完成
          if (orderDetail.pay_status === 1 && data.order_status === 4) {
              const { travel_mode_fee, staff_amount } = orderDetail
              let total_amount = parseFloat(travel_mode_fee) + parseFloat(staff_amount)
              const insertData = {
                  order_id: id,
                  order_no: orderDetail.order_no,
                  staff_id: orderDetail.staff_id,
                  amount: total_amount,
                  project_amount: staff_amount,
                  travel_mode_fee: travel_mode_fee,
                  type: 1,
                  desc: '订单完成',
              }
              // 并添加记录
              await this.ctx.service.staffBalance.add(insertData)
          }
          await this.ctx.model[ModelName].update({
              ...data,
              staff_ratio: data.staff_id ? staffDetail.settlement_ratio  : 0,
              settlement_status: 1
          }, {
              where: {id},
              transaction
          })

          await transaction.commit();
          return true;
      } catch (e) {
          await transaction.rollback();
          console.log(e)
          throw new Error(e)
      }
  }
    /**
     * 微信支付v3 下单签名值生成
     * @param {string} method 请求方法
     * @param {string} url  微信小程序下单官方api
     * @param {number} timestamp 时间戳 秒级
     * @param {string} nonce_str 随机字符串
     * @param {Object} order 主体（订单）信息
     */
    createOrderSign(method, url, timestamp, nonce_str, order) {
        // 签名串
        let signStr = `${method}\n${url}\n${timestamp}\n${nonce_str}\n${JSON.stringify(
            order
        )}\n`;
        // 读取API证书文件内容 apiclient_key.pem的内容
        const filepath = path.join('app', '/public/apiclient_key.pem');
        let cert = fs.readFileSync(filepath, "utf-8");
        // 创建使用 RSA 算法和 SHA-256 散列算法的签名对象
        let sign = crypto.createSign("RSA-SHA256");
        // 对签名串进行加密处理
        sign.update(signStr);
        return sign.sign(cert, "base64");
    }
    async refund(data) {
        if (!data.id || !data.back_amount || !data.back_result) {
            throw new Error('参数错误')
        }
        // 更新订单状态
        await this.update(data.id, {
            ...data,
            back_no: 'TC' + createOrderNumber()
        })
        const order = await this.findOne(data.id)
        if (!order) {
            throw new Error('订单不存在')
        }
        if (order.dataValues.pay_amount === 0) {
            await this.update(data.id, {
                pay_status: 4
            })
            return
        }
        const { back_no, back_amount, pay_amount, back_result, order_no } = order.dataValues
        let refundsParams = {
            out_trade_no: order_no,
            out_refund_no: back_no,
            reason: back_result,
            notify_url: config.notify_url_refund,
            amount: {
                refund: Math.ceil(back_amount * 100),
                total: Math.ceil(pay_amount * 100),
                currency: 'CNY'
            }
        }
        let timeStamp = Math.floor(new Date().getTime() / 1000)
        let nonceStr = generateNonceStr(32)
        const Authorization = `WECHATPAY2-SHA256-RSA2048 mchid="${config.mch_id}",nonce_str="${nonceStr}",signature="${this.createOrderSign('POST',
            '/v3/refund/domestic/refunds',
            timeStamp,
            nonceStr,
            refundsParams
        )}",timestamp="${timeStamp}",serial_no="${config.serial_no}"`
        try {
            const refundsRes = await this.ctx.curl('https://api.mch.weixin.qq.com/v3/refund/domestic/refunds', {
                method: "post",
                data: refundsParams,
                headers: {
                    Authorization,
                    Accept: 'application/json',
                    'Content-Type': 'application/json',
                },
                dataType: 'json'
            })
            if (refundsRes.status !== 200) {
                throw new Error(refundsRes.data.message || '退款失败 ')
            }
            let pay_status = 3
            if (refundsRes.data.status === 'SUCCESS') {
                pay_status = 4
            }
            await this.update(data.id, {
                refund_id: refundsRes.data.refund_id,
                pay_status
            })
            return true
        } catch (e) {
            throw new Error(e)
        }
    }
    async refundH5(data) {
        if (!data.id || !data.back_amount || !data.back_result) {
            throw new Error('参数错误')
        }
        // 更新订单状态
        await this.update(data.id, {
            ...data,
            back_no: 'TC' + createOrderNumber()
        })
        const order = await this.findOne(data.id)
        if (!order) {
            throw new Error('订单不存在')
        }
        const { back_no, back_amount, pay_amount, back_result, order_no } = order.dataValues
        let refundsParams = {
            out_trade_no: order_no,
            out_refund_no: back_no,
            reason: back_result,
            notify_url: configH5.notify_url_refund,
            amount: {
                refund: Math.ceil(back_amount * 100),
                total: Math.ceil(pay_amount * 100),
                currency: 'CNY'
            }
        }
        let timeStamp = Math.floor(new Date().getTime() / 1000)
        let nonceStr = generateNonceStr(32)
        const Authorization = `WECHATPAY2-SHA256-RSA2048 mchid="${configH5.mch_id}",nonce_str="${nonceStr}",signature="${this.createOrderSign('POST',
            '/v3/refund/domestic/refunds',
            timeStamp,
            nonceStr,
            refundsParams
        )}",timestamp="${timeStamp}",serial_no="${configH5.serial_no}"`
        try {
            const refundsRes = await this.ctx.curl('https://api.mch.weixin.qq.com/v3/refund/domestic/refunds', {
                method: "post",
                data: refundsParams,
                headers: {
                    Authorization,
                    Accept: 'application/json',
                    'Content-Type': 'application/json',
                },
                dataType: 'json'
            })
            if (refundsRes.status !== 200) {
                throw new Error(refundsRes.data.message || '退款失败 ')
            }
            let pay_status = 3
            if (refundsRes.data.status === 'SUCCESS') {
                pay_status = 4
            }
            await this.update(data.id, {
                refund_id: refundsRes.data.refund_id,
                pay_status
            })
            return true
        } catch (e) {
            throw new Error(e)
        }
    }

  /**
   * 订单号更新支付状态
   */
  async updatePayStatus(order_no) {
    return await this.ctx.model[ModelName].update({
      pay_status: 1,
      pay_time: dayjs().format('YYYY-MM-DD HH:mm:ss')
    }, {
      where: {
        order_no
      }
    });
  }

  /**
   * 根据id删除
   * @param id
   */
  async deleteById(id) {
     return  await this.ctx.model[ModelName].update({  is_del: 1 }, { where: { id } });
  }
    async cancelOrder() {
        // 获取所有未支付的订单
        const orderList = await this.ctx.model.OrderGoods.findAll({
            where: {
                pay_status: 0,
                order_status: 0
            }
        })
        // 允许取消的列表
        // 创建时间距离当前时间大于15分钟
        const allowList = orderList.filter(el => {
            return new Date(el.create_time).getTime() + 5 * 60 * 1000 < new Date().getTime()
        })
        for (let i = 0; i < allowList.length; i++) {
            const order = allowList[i]
            this.ctx.model.OrderGoods.update({
                order_status: -1,
            }, {
                where: {
                    id: order.id
                }
            })
        }
    }

}

module.exports = RouterService;
